package cn.loioi.config;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.filter.authc.UserFilter;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import cn.loioi.web.components.shiro.CustomAuthorizingRealm;
import cn.loioi.web.components.shiro.CustomFormAuthenticationFilter;
import cn.loioi.web.components.shiro.CustomUserFilter;
import net.sf.ehcache.CacheManager;

/**
 * @描述 :权限框架配置
 * @文件 :ShiroSourceConfig.java
 * @作者 :cn.loioi
 * @创建时间 :2016年10月13日 下午12:55:48
 */
@Order(2)
@Configuration
public class ShiroSourceConfig {
	/** 是否使用验证码 */
	public static final boolean USE_TONKEY = false;
	/** 账号的字段名 */
	public static final String ACCOUNT_PARAM = "account";
	/** 密码的字段名 */
	public static final String PASSWORD_PARAM = "password";
	/** 验证码的字段名 */
	public static final String TONKEY_PARAM = "tonkeCode";
	/** 记住我的字段名 */
	public static final String REMEMBER_ME_PARAM = "rememberMe";
	/** 登录地址 */
	public static final String LOGIN_URL = "/admin/login.jspx";
	/** 登录成功跳转地址 */
	public static final String SUCCCESS_URL = "/admin/index.jspx";

	@Autowired
	@Qualifier("net.sf.ehcache.CacheManager")
	private CacheManager cacheManager;

	/**
	 * 缓存管理器 使用Ehcache实现,shrio专用
	 * @return
	 */
	@Bean(name = "org.apache.shiro.cache.ehcache.EhCacheManager")
	public EhCacheManager ehCacheManager() {
		EhCacheManager ehCacheManager = new EhCacheManager();
		ehCacheManager.setCacheManager(cacheManager);
		return ehCacheManager;
	}

	/**
	 * 密码规则-凭证管理
	 * @return
	 */
	@Bean
	public SimpleCredentialsMatcher credentialsMatcher() {
		HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
		credentialsMatcher.setHashAlgorithmName("MD5");
		credentialsMatcher.setHashIterations(1);
		credentialsMatcher.setStoredCredentialsHexEncoded(true);
		return credentialsMatcher;
	}

	/**
	 * Realm实现
	 * @return
	 */
	@Bean
	public Realm customRealm() {
		CustomAuthorizingRealm realm = new CustomAuthorizingRealm();
		realm.setCredentialsMatcher(credentialsMatcher());
		return realm;
	}

	/**
	 * 会话ID生成器
	 * @return
	 */
	@Bean
	public JavaUuidSessionIdGenerator sessionIdGenerator() {
		return new JavaUuidSessionIdGenerator();
	}

	/**
	 * 会话Cookie模板
	 * @return
	 */
	@Bean
	public SimpleCookie sessionIdCookie() {
		SimpleCookie cookie = new SimpleCookie();
		cookie.setHttpOnly(true);
		cookie.setName("token");
		return cookie;
	}

	@Bean
	public SimpleCookie rememberMeCookie() {
		SimpleCookie cookie = new SimpleCookie();
		cookie.setHttpOnly(true);
		cookie.setMaxAge(2592000);// 30天
		cookie.setName("rememberMe");
		return cookie;
	}

	/**
	 * rememberMe管理器
	 * @return
	 */
	@Bean
	public CookieRememberMeManager rememberMeManager() {
		CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
		rememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
		rememberMeManager.setCookie(rememberMeCookie());
		return rememberMeManager;
	}

	/**
	 * 会话DAO
	 * @return
	 */
	@Bean
	public EnterpriseCacheSessionDAO sessionDAO() {
		EnterpriseCacheSessionDAO sessionDAO = new EnterpriseCacheSessionDAO();
		sessionDAO.setSessionIdGenerator(sessionIdGenerator());
		sessionDAO.setActiveSessionsCacheName("shiroActiveSessionCache");
		return sessionDAO;
	}

	/**
	 * 会话管理器
	 * @return
	 */
	@Bean
	public DefaultWebSessionManager sessionManager() {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setGlobalSessionTimeout(1800000);
		sessionManager.setSessionValidationInterval(1800000);
		sessionManager.setDeleteInvalidSessions(true);
		sessionManager.setSessionDAO(sessionDAO());
		sessionManager.setSessionIdCookieEnabled(true);
		sessionManager.setSessionIdCookie(sessionIdCookie());
		return sessionManager;
	}

	/**
	 * 安全管理器
	 * @return
	 */
	@Bean
	public DefaultWebSecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(customRealm());
		securityManager.setCacheManager(ehCacheManager());
		securityManager.setSessionManager(sessionManager());
		securityManager.setRememberMeManager(rememberMeManager());
		return securityManager;
	}

	/**
	 * 配置 表单过滤器
	 * @return
	 */
	@Bean
	public FormAuthenticationFilter authcFilter() {
		CustomFormAuthenticationFilter filter = new CustomFormAuthenticationFilter();
		filter.setLoginUrl(LOGIN_URL);
		filter.setUseTonkey(USE_TONKEY);
		filter.setSuccessUrl(SUCCCESS_URL);
		filter.setTonkeyParam(TONKEY_PARAM);
		filter.setUsernameParam(ACCOUNT_PARAM);
		filter.setPasswordParam(PASSWORD_PARAM);
		filter.setRememberMeParam(REMEMBER_ME_PARAM);
		return filter;
	}

	/**
	 * 配置 用户登录过滤器
	 * @return
	 */
	@Bean
	public UserFilter userFilter() {
		CustomUserFilter filter = new CustomUserFilter();
		filter.setLoginUrl(LOGIN_URL);
		return filter;
	}

	/**
	 * Shiro的退出过滤器
	 * @return
	 * @throws Exception
	 */
	@Bean
	public LogoutFilter logoutFilter() {
		return new LogoutFilter();
	}

	/**
	 * Shiro的Web过滤器
	 * @return
	 * @throws Exception
	 */
	@Bean
	public Object shiroFilter() throws Exception {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager());
		shiroFilterFactoryBean.setLoginUrl(LOGIN_URL);

		Map<String, Filter> filterMap = new HashMap<>();
		filterMap.put("authc", authcFilter());
		filterMap.put("user", userFilter());
		filterMap.put("logout", logoutFilter());
		shiroFilterFactoryBean.setFilters(filterMap);
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap());
		return shiroFilterFactoryBean.getObject();
	}

	/**
	 * 授权 注解配置
	 * @return
	 */
	@Bean
	public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		return advisorAutoProxyCreator;
	}

	/**
	 * 授权 注解配置
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor attributeSourceAdvisor() {
		AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		attributeSourceAdvisor.setSecurityManager(securityManager());
		return attributeSourceAdvisor;
	}

	private Map<String, String> filterChainDefinitionMap() {
		Map<String, String> map = new HashMap<>();
		map.put("/api/**", "anon");
		map.put("/anon/**", "anon");
		map.put("/assets/**", "anon");
		map.put("/upload/**", "anon");
		map.put("/druid/**", "anon");
		map.put("/favicon.ico", "anon");
		map.put("/**.js.map", "anon");
		map.put("/logout", "logout");
		map.put(LOGIN_URL, "authc");
		map.put("/**", "user");
		return map;
	}
}